package cn._2dland.uploader.qq;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.apache.commons.httpclient.params.HttpMethodParams;

import cn._2dland.uploader.CountingMultipartRequestEntity;
import cn._2dland.uploader.HttpException;
import cn._2dland.uploader.UploadClient;
import cn._2dland.uploader.UploadHandler;
import cn._2dland.uploader.UploadTask;
import cn._2dland.uploader.utils.HttpUtils;
import cn._2dland.uploader.utils.Logger;

public class QQClient extends UploadClient {
	/** 身份处理API */
	private static final String CHECK_URL = "http://ptlogin2.qq.com/check?appid=5000501";
	/** 登录API */
	private static final String LOGIN_URL = "http://ptlogin2.qq.com/login?aid=5000501&u1=http%3A%2F%2Fact3.bb.qq.com%2F4015%2Fmy.do&h=1&ptredirect=1&ptlang=2052&from_ui=1&dumy=&fp=loginerroralert&mibao_css=";
	/** 提交信息API */
	private static final String POST_URL = "http://act3.bb.qq.com/4015/join/savedesc.do";
	/** 上传API */
	private static final String UPLOAD_URL = "http://act3.bb.qq.com/4015/upload/stepflashvideo.do?workid=";

	/** 为模拟flash上传，使用一个独立的httpclient */
	private HttpClient flashClient = null;
	
	public QQClient(String user, String pass) {
		super(user, pass);

		flashClient = new HttpClient();
	}

	public boolean login() {
		try {
			Logger.writec("登录帐号 " + username + " ...");

			// 获取验证码
			String vfrCode = getVerifyCode();
			Logger.writec("verify code: " + vfrCode);

			// 登录
			StringBuffer loginUrl = new StringBuffer(LOGIN_URL)
									.append("&u=").append(username)
									.append("&p=").append(QQUtils.generateKey(vfrCode, password))
									.append("&verifycode=").append(vfrCode);
			GetMethod loginGet = new GetMethod(loginUrl.toString());
			int respCode = client.executeMethod(loginGet);

			// 获取登录结果
			if(respCode != HttpStatus.SC_OK)
				throw new HttpException(respCode);
			String result = HttpUtils.readResponseStream(loginGet);
			loginGet.releaseConnection();
			result = result.substring(result.indexOf("(") + 1, result.lastIndexOf(")"));

			// 处理登录结果
			String tmp[] = result.split(",");
			String status = QQUtils.removeQuotes(tmp[0]);
			bLogin = "0".equals(status);

			// 提示结果
			String prompt = QQUtils.removeQuotes(tmp[4]);
			Logger.writec(prompt);
		} catch (Exception e) {
			Logger.writec("登录时发生异常，请查看错误日志文件...");
			Logger.error(e);
		}
		return bLogin;
	}

	public boolean upload(UploadTask task) {
		boolean bOK = false;
		try {
			// 提交信息
			Logger.writec("提交视频信息...");
			PostMethod infoPost = new PostMethod(POST_URL);
			//infoPost.getParams().setContentCharset("gbk");
			infoPost.addParameters(new NameValuePair[]{
					new NameValuePair("info[title]", task.title),
					new NameValuePair("info[field_4]", task.category),
					new NameValuePair("info[field_5]", task.descript),
					new NameValuePair("info[id]", ""),
					new NameValuePair("info[field_11]", ""),
					new NameValuePair("info[video_dir]", ""),
					new NameValuePair("opt", "update"),
					new NameValuePair("_", "")
			});
			client.executeMethod(infoPost);
			String workid = QQUtils.readStream(infoPost.getResponseBodyAsStream(), "utf-8");
			infoPost.releaseConnection();

			// 上传文件
			Logger.writec("信息提交完成！开始上传视频 " + task.fileName + " ...");
			PostMethod uploadPost = new PostMethod(UPLOAD_URL + workid);
			uploadPost.getParams().setParameter(HttpMethodParams.USER_AGENT, "Shockwave Flash");
			Part[] parts = {
					new StringPart("Filename", task.fileName, "gbk"),
					new StringPart("skey", getCookieValue("skey"), "gbk"),
					new StringPart("uin", getCookieValue("uin"), "gbk"),
					new FilePart("Filedata", task.file, "application/octet-stream", "gbk"),
					new StringPart("Upload", "Submit Query", "gbk")
			};
			uploadPost.setRequestEntity(new CountingMultipartRequestEntity(parts, client.getParams(), task.file.length(),  new UploadHandler()));
			int respCode = flashClient.executeMethod(uploadPost);
			uploadPost.releaseConnection();

			bOK = (respCode == HttpStatus.SC_OK);
			if(bOK) {
				Logger.writecf("视频上传成功：" + task.fileName);
			} else {
				Logger.writec("视频上传失败...");
			}
		} catch (Exception e) {
			Logger.writec("上传时发生异常，请查看错误日志文件...");
			Logger.error(e);
		}
		return bOK;
	}

	/**
	 * 获取验证码
	 * @return
	 * @throws Exception
	 */
	private String getVerifyCode() throws Exception {
		// 构造请求
		StringBuffer buf = new StringBuffer(CHECK_URL)
								.append("&uin=").append(username)
								.append("&r=").append(Math.random());
		GetMethod checkGet = new GetMethod(buf.toString());
		int respCode = client.executeMethod(checkGet);
		if(respCode != HttpStatus.SC_OK)
			throw new HttpException(respCode);

		// 获取相应结果
		String result = HttpUtils.readResponseStream(checkGet);
		checkGet.releaseConnection();

		// 解析返回结果
		result = result.substring(result.indexOf("(") + 1, result.indexOf(")"));
		String status = result.substring(0, result.indexOf(","));
		status = QQUtils.removeQuotes(status);
		String vfrCode = result.substring(result.indexOf(",") + 1);
		vfrCode = QQUtils.removeQuotes(vfrCode);
		if(!"0".equals(status)) {
			vfrCode = getVirifyCodeFromImage(vfrCode);
		}
		return vfrCode;
	}

	/**
	 * 显示验证码图片，并获取用户输入的验证码
	 * @param vcType
	 * @return
	 */
	private String getVirifyCodeFromImage(String vcType) {
		Logger.writec("请输入图中的验证码...");

		// 在对话框中显示验证码
		VerifyCodeDialog vcDlg = new VerifyCodeDialog(null, client);
		vcDlg.setLocationRelativeTo(null);
		vcDlg.loadImage(username, vcType);
		vcDlg.setVisible(true);

		// 获取验证码
		return vcDlg.getVerifyCode();
	}

	/**
	 * 读取cookie中的值
	 * @param name
	 * @return
	 */
	private String getCookieValue(String name) {
		if(name == null)
			return null;

		String value = null;
		Cookie[] cookies = client.getState().getCookies();
		for(Cookie ck : cookies) {
			if(name.equals(ck.getName())) {
				value = ck.getValue();
				break;
			}
		}
		return value;
	}
}
